#!/usr/bin/env python

"""
urbanmob 1.0

Authors: Olafur R. Helgason (olafur.helgason@gmail.com and
         Kristjan V. Jonsson (kristjanvj@gmail.com)
         (c) Olafur R. Helgason (2007)
        
Part of the MobiTrace toolbox of the OppoNet project. OppoNet is a open-source
effort to create software and modules for support of modeling of opportunistic
wireless systems in OMNeT++. Project hompage: http://www.ee.kth.se/lcn/opponet.

Urbanmob generates a xml mobility file from a topology description using the node
number and arrival rate specified on the command line.

Usage:
  urbanmob [options]
    options:
    -h|--help:          Display help text.
    -n|--nodes:         Number of nodes to generate
    -a|--arrival-rate:  Arrival rate of nodes at each entry
    -t|--topology-file: Topology specification file
    -l|--log-level:     Log level for debug purposes. 0=none, 1=events, 2=xml
    
  Example:
    urbanmob --nodes 10 --arrival-rate 0.2 --topology-file crossroads.topo
"""

# =============================================================================
#
# LICENSING
#
# =============================================================================
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# =============================================================================

__AUTHOR__  = "Olafur R. Helgason"
__AUTHOR__  = "Kristjan V. Jonsson"
__VERSION__ = 1.0

MIN_SPEED = 0.5

import sys
import os;
import getopt
import string
from topo import *
from generate import *
from random import *
from decimal import *
from tracexml import *
from tracesupport import *


def generate(basename,nodes,t,rt,entries,arrival_rate,debug=0):
  """
  Generates random routes for the specified number of nodes.
  The topology and routing probabilities t and rt are taken as inputs, along
  with the designated entries into the area and an arrival rate.
  Debug controls the output: 
    0: silent
    1: Prints generated events
    2: dumps the xml after creation.
  """
  
  v_min = 0.5
  v_max = 1.5
  num_generators = len(entries)
  
  doc,root = createRootNode()
    
  if debug>0:print "Generating for rate " + str(arrival_rate)
  ng = NodeGeneration(num_generators, [arrival_rate] * num_generators) 

  seed()
  xmlname = basename + "." + str(arrival_rate) + ".xml"

  gen_events = ng.generate(nodes)
  nodelist = t.nodes()
  node_id = 1
  
  for gen_ev in gen_events:
    entry_time = gen_ev[0]
    entry_node = filter(lambda n: n.id() == entries[gen_ev[1]], nodelist)[0] 
    if debug>=1: print "CREATE t=%.2f n=%s e=%s pos=(%.2f,%.2f)" % \
      (entry_time,node_id,entry_node,entry_node.pos().x,entry_node.pos().y);
    addCreateNode(doc,root,node_id,entry_time,entry_node.pos().x,entry_node.pos().y);            
    path = random_path(rt, entry_node.id())
    time = entry_time
    for node in path:
      if(path.index(node) == 0):
        continue
      src = filter(lambda n: n.id() == path[path.index(node)-1],nodelist)[0]
      dst = filter(lambda n: n.id() == node, nodelist)[0]
      dist = Position.distance(src.pos(), dst.pos())
      speed = uniform(v_min, v_max)
      traveltime = dist/speed
      if debug>=1: print "WAYPOINT t=%.2f n=%s pos=(%.2f,%.2f) sp=%.2f" % \
        (time,node_id,dst.pos().x,dst.pos().y,speed);
      addWaypointNode(doc,root,node_id,time,dst.pos().x,dst.pos().y,speed);
      time += traveltime
    if debug>=1: print "DESTROY t=%.2f n=%s" % (time,node_id);
    addDestroyNode(doc,root,node_id,time);
    node_id += 1
    
  # Save the trace
  if debug>=2: showDocument(doc)
  saveDocument(doc,xmlname);        


#
# Main method. 
# This is the body of the program. Handles reading and processing of command line options.
#
def main(argv=None):
  if argv is None:
    argv = sys.argv

    print "\n";
    print "UrbanMobility";
    print "Mobility trace generator";
    try:
      try:  
        opts, args = getopt.getopt( argv[1:], "hn:a:t:l:", \
                                    ["help","nodes=","arrival-rate=","topology-file=","log-level="])                
      except getopt.error, msg:
        raise Usage(msg)
    except Usage, err:
      print >>sys.stderr, err.message
      print >>sys.stderr, "for help use --help"
      return 2
                
    nodes = 0;                 
    arrival_rate = 0.0;         
    topo_file = "";   
    basename = "";    
    log_level = 0;
                
    # Process the command line options
    for o, a in opts:
      if o in ("-h", "--help"):
        print __doc__
        print "\n"
        sys.exit(0)         
      if o in ("-n", "--nodes"):
        try:
          nodes = string.atoi(a);                                      
        except ValueError:
          print >>sys.stderr, "Invalid value for number of nodes";
          return 2;
      if o in ("-a", "--arrival-rate"):                 
        try:
          arrival_rate = string.atof(a);                                      
        except ValueError:
          print >>sys.stderr, "Invalid value for arrival rate";
          return 2;
      if o in ("-t", "--topology-file"):
        topo_file = a;
        if not os.path.exists(topo_file):
          print >>sys.stderr, "Topology file not found";
          return 2;
        basename,ext = topo_file.split(".");
      if o in ("-l", "--log-level"):
        try:
          log_level = string.atof(a);                                      
        except ValueError:
          print >>sys.stderr, "Invalid value for log level";
          return 2;        
                         
    if nodes < 1:
      print >>sys.stderr, "No nodes specified";
      return 2;
      
    if arrival_rate <= 0.0:
      print >>sys.stderr, "Invalid arrival rate";
      return 2;
    
    if topo_file == "":
      print >>sys.stderr, "Unspecified topology file";
      return 2;
    
    print;
    print "  Nodes:         ", nodes;
    print "  Arrival rate:  ", arrival_rate;      
    print "  Topology file: ", topo_file;
    print;
                     
    t = None;
    rt = {};
    entries = [];
    tparser = TopoParser();
    try:
      # Parse the topology file 
      t,rt,entries = tparser.parse(topo_file,log_level)             
      if log_level>0: t.debug(); # Show the topology debug message
      verify_rtable(rt,t)             
    except Exception, ex:
      print ex;
      return 2;             
                                                                                                
    # Generate the trace                                                                
    generate(basename,nodes,t,rt,entries,arrival_rate,log_level)
      
if __name__ == "__main__":
  sys.exit(main())  
  
  
